#pragma once

#include "RdcBuffer.h"
#include "ServerChannelCoreImpl.h"

namespace rdc_transport
{
    template<class SessionWatcherStrategy>
    class ServerChannelCore 
        : public IServerVirtChannelCallback
        , public IVirtChannel
        , public IReader

    {
    private:
        typedef std::auto_ptr<SessionWatcherStrategy> pSessionWatcherStrategy;
    
    public:
        ServerChannelCore(const char* channelName, pSessionWatcherStrategy sw)
            : m_channelName(channelName)
            , m_serverCoreImpl(new ServerChannelCoreImpl(m_channelName))
            , m_sw(sw)
            , m_coreStateTerminated(false)
        {
            m_sw->AddDisconnectHandler(boost::bind(&ServerChannelCore<SessionWatcherStrategy>::OnDisconnect, this));
            m_sw->AddReconnectHandler(boost::bind(&ServerChannelCore<SessionWatcherStrategy>::OnReconnect, this));
        }
        ~ServerChannelCore()
        {
            Terminate();
        }

    public:
        void OnDisconnect()
        {
            Terminate();
            boost::unique_lock<boost::shared_mutex> l(m_reconnectLock);

            m_serverCoreImpl.reset();
        }

        void OnReconnect()// can throw run time error.
        {
            Terminate();
            boost::unique_lock<boost::shared_mutex> l(m_reconnectLock);

            m_serverCoreImpl.reset(new ServerChannelCoreImpl(m_channelName));
            m_coreStateTerminated = false;
        }

    public:
        void Write(Buffer* pBuffer)
        {
            try
            {
                WriteImpl(pBuffer);
            }
            catch (std::exception&)
            {
            	// try reconnect.
                OnReconnect();
                WriteImpl(pBuffer);
            }
        }

        void WriteImpl(Buffer* pBuffer)
        {
            boost::shared_lock<boost::shared_mutex> l(m_reconnectLock);

            if(m_coreStateTerminated)
                throw std::runtime_error(std::string(__FUNCTION__) + " Terminated");
            
            m_serverCoreImpl->Write(pBuffer);
        }

        void ReadFile(PCHAR pBuffer, DWORD dwInSize, PDWORD pdwOutSize)
        {
            boost::shared_lock<boost::shared_mutex> l(m_reconnectLock);

            if(m_coreStateTerminated)
                throw std::runtime_error(std::string(__FUNCTION__) + " Terminated");

            m_serverCoreImpl->ReadFile(pBuffer, dwInSize, pdwOutSize);
        }
        
        SessionWatcherStrategy* GetSessionInfo()
        {
            return m_sw.get();
        }

    private:
        void Terminate()
        {
            if(!m_reconnectLock.try_lock())
            {
                m_serverCoreImpl->Terminate();
            }
            else
            {
                m_coreStateTerminated = true;
                m_reconnectLock.unlock();
            }
        }

    private:
        std::string m_channelName;
        std::auto_ptr<ServerChannelCoreImpl> m_serverCoreImpl;
        pSessionWatcherStrategy m_sw;

        boost::shared_mutex m_reconnectLock;
        bool m_coreStateTerminated;
    };
}